package org.kernely.stream.dao;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.kernely.persistence.service.SessionService;
import org.kernely.security.persistence.User;
import org.kernely.stream.persistence.Message;
import org.kernely.stream.persistence.Stream;
import org.osgi.service.component.ComponentContext;

/**
 *	DAO which contains methods to use Message entities.
 */
@SuppressWarnings("unchecked")
public class MessageDAO {
	/**
	 * SessionService service
	 */
	private static SessionService service;
	
	/**
	 * The message dao instance
	 */
	private static MessageDAO instance;

	/**
	 * Store the message dao instance 
	 * @return the message dao
	 */
	public static MessageDAO getInstance() {
		return instance;
	}
	
	/**
	 * Set the persistence session service
	 * @param sessionService the session service to set
	 */
	public final void setPersistenceService(SessionService sessionService) {
		service = sessionService;
	}

	/**
	 * Activate the component, called by SC runtime
	 * @param ctxt the activation context
	 */
	protected final void activate(ComponentContext ctxt) {
		instance = this;
	}
	
	/**
	 * Gets the session service.
	 * 
	 * @return the session service
	 */
	public static SessionService getService() {
		return service;
	}

	/**
	 * Sets the session service.
	 * 
	 * @param service
	 *            the session service to set
	 */
	public static void setService(SessionService service) {
		MessageDAO.service = service;
	}
	
	/**
	 * Save a new message in database.
	 * @param m The message
	 */
	public final void saveMessage(Message m){
		Session session = service.getSession();
		session.save(m);
	}
	
	/**
	 * Delete an existing message
	 * @param message : the message to delete
	 */
	public final void deleteMessage(Message message){
		Session session = service.getSession();
		session.delete(message);
	}
	
	/**
	 * Update an existing message
	 * @param message The message to update.
	 */
	public final void updateMessage(Message message){
		Session session = service.getSession();
		session.merge(message);
	}
	
	/**
	 * Get messages from a specific index, with a maximum number of result.
	 * @param begin	The index of the message to get.
	 * @param nbresult Max number of results.
	 * @param filter	The stream in which search the messages.
	 * @return
	 */
	public final Set<Message> getUserMessages(User u, int begin, int nbresult, Stream filter){
		Session session = service.getSession();
		String req;
		if(filter == null){
			req = "SELECT * FROM kernely_message , kernely_stream, kernely_stream_subscription, user  WHERE kernely_message.fk_stream_id = kernely_stream.stream_id AND kernely_stream.stream_id = kernely_stream_subscription.fk_stream AND kernely_stream_subscription.fk_user = user.user_id AND message_parent IS NULL AND user.user_id = "+ u.getId() +" ORDER BY message_id DESC LIMIT "+ begin +", "+ nbresult + "";
		}
		else{
			req = "SELECT * FROM kernely_message , kernely_stream, kernely_stream_subscription, user  WHERE kernely_message.fk_stream_id = kernely_stream.stream_id AND kernely_stream.stream_id = kernely_stream_subscription.fk_stream AND kernely_stream_subscription.fk_user = user.user_id AND message_parent IS NULL AND user.user_id = "+ u.getId() +" AND fk_stream_id = "+ filter.getId() +" ORDER BY message_id DESC LIMIT "+ begin +", "+ nbresult + "";			
		}
		Query query = session.createSQLQuery(req).addEntity(Message.class);

		return new HashSet<Message>(query.list());
	}
	
	/**
	 * Returns all messages which are older than the message m
	 * @param u : user concerned by the messages
	 * @param m : Point where research begins
	 * @param nbresult : number of messages desired
	 * @return a set containing all messages older than m
	 */
	public final Set<Message> getNextMessages(User u, Message m, int nbresult, Stream filter){
		Session session = service.getSession();
		String req;
		if(filter == null){
			req = "SELECT * FROM kernely_message , kernely_stream, kernely_stream_subscription, user  WHERE kernely_message.fk_stream_id = kernely_stream.stream_id AND kernely_stream.stream_id = kernely_stream_subscription.fk_stream AND kernely_stream_subscription.fk_user = user.user_id AND message_parent IS NULL AND user.user_id = "+ u.getId() +" AND message_id < " + m.getId() + " ORDER BY message_id DESC LIMIT "+ nbresult + "";
		}
		else{
			req = "SELECT * FROM kernely_message , kernely_stream, kernely_stream_subscription, user  WHERE kernely_message.fk_stream_id = kernely_stream.stream_id AND kernely_stream.stream_id = kernely_stream_subscription.fk_stream AND kernely_stream_subscription.fk_user = user.user_id AND message_parent IS NULL AND user.user_id = "+ u.getId() +" AND message_id < " + m.getId() + " AND fk_stream_id = "+ filter.getId() +" ORDER BY message_id DESC LIMIT "+ nbresult + "";			
		}
		Query query = session.createSQLQuery(req).addEntity(Message.class);

		return new HashSet<Message>(query.list());
	}
	
	/**
	 * Retrieve all messages
	 * @return
	 */
	public final Set<Message> getAllMessages(){
		Session session = service.getSession();
		Criteria crit = session.createCriteria(Message.class);
		return new HashSet<Message>(crit.list());
	}
	
	/**
	 * Retrieve all messages which are more recent than m
	 * @param u : user concerned by the messages
	 * @param m : message where research begins
	 * @return a set of messages more recent than m
	 */
	public final Set<Message> getAllRecentMessage(User u, Message m, Stream filter){
		Session session = service.getSession();
		String req = "";
		if(filter == null){
			if(m != null){
				req = "SELECT * FROM kernely_message , kernely_stream, kernely_stream_subscription, user  WHERE kernely_message.fk_stream_id = kernely_stream.stream_id AND kernely_stream.stream_id = kernely_stream_subscription.fk_stream AND kernely_stream_subscription.fk_user = user.user_id AND message_parent IS NULL AND user.user_id = "+ u.getId() +" AND message_id > " + m.getId() + " ORDER BY message_id DESC";
			}
			else{
				req = "SELECT * FROM kernely_message , kernely_stream, kernely_stream_subscription, user  WHERE kernely_message.fk_stream_id = kernely_stream.stream_id AND kernely_stream.stream_id = kernely_stream_subscription.fk_stream AND kernely_stream_subscription.fk_user = user.user_id AND message_parent IS NULL AND user.user_id = "+ u.getId() +"  ORDER BY message_id DESC";
			}
		}
		else{
			if(m != null){
				req = "SELECT * FROM kernely_message , kernely_stream, kernely_stream_subscription, user  WHERE kernely_message.fk_stream_id = kernely_stream.stream_id AND kernely_stream.stream_id = kernely_stream_subscription.fk_stream AND kernely_stream_subscription.fk_user = user.user_id AND message_parent IS NULL AND user.user_id = "+ u.getId() +" AND message_id > " + m.getId() + " AND fk_stream_id = "+ filter.getId() +" ORDER BY message_id DESC";
			}
			else{
				req = "SELECT * FROM kernely_message , kernely_stream, kernely_stream_subscription, user  WHERE kernely_message.fk_stream_id = kernely_stream.stream_id AND kernely_stream.stream_id = kernely_stream_subscription.fk_stream AND kernely_stream_subscription.fk_user = user.user_id AND message_parent IS NULL AND user.user_id = "+ u.getId() +" AND fk_stream_id = "+ filter.getId() +" ORDER BY message_id DESC";
			}
		}
		Query query = session.createSQLQuery(req).addEntity(Message.class);;

		return new HashSet<Message>(query.list());
	}
	
	/**
	 * Find a message wih its id
	 * @param id The id of the message
	 * @return The message
	 */
	public final Message findMessageById(int id){
		Session session = service.getSession();
		Criteria crit = session.createCriteria(Message.class);
		crit.add(Restrictions.like("id", id));
		List<Message> list = crit.list();
		Message message;
		if(list.isEmpty()){
			message = null;
		}
		else{
			message = (Message) list.get(0);
		}
		return message;
	}
	
	/**
	 * Gets the message added as favorites by the user.
	 * @param user The user which favorites are searched.
	 * @return A set which contains all messages marked as favorites.
	*/
	public final Set<Message> getFavorites(User user){
		Set<Message> favorites = new HashSet();
		for (Message message : MessageDAO.getInstance().getAllMessages()){
			for (User u : message.getFavoriteUsers()){
				if (u.equals(user)){
					favorites.add(message);
				}
			}
		}
		return favorites;
	}

	 /** Retrieve all comments about a given message
	 * @param message : the message
	 * @return a set of comments relative to this message
	 */
	public final Set<Message> getAllCommentsFromMessage(Message message){
		Session session = service.getSession();
		Criteria crit = session.createCriteria(Message.class);
		crit.add(Restrictions.like("message", message));
		return new HashSet<Message>(crit.list());
	}
	
	/**
	 * Get messages in streams subscribed by the user, which contains a specific string.
	 * @param u The user (to get his subscribed streams).
	 * @param search The contain searched in messages.
	 * @return
	 */
	public final Set<Message> getSearchMessages(User u , String search){
		Session session = service.getSession();
		String req = "SELECT * FROM kernely_message , kernely_stream, kernely_stream_subscription, user  WHERE kernely_message.fk_stream_id = kernely_stream.stream_id AND kernely_stream.stream_id = kernely_stream_subscription.fk_stream AND kernely_stream_subscription.fk_user = user.user_id AND message_parent IS NULL AND content like '%"+search+"%' AND user.user_id = "+ u.getId() +" ORDER BY message_id DESC";
		Query query = session.createSQLQuery(req).addEntity(Message.class);;

		return new HashSet<Message>(query.list());
	}
}
